package com.wang.common.util;

import lombok.extern.log4j.Log4j2;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * poi相关的工具类
 *
 * @author wangsh
 */
@Component
@Log4j2
public class PoiUtil {
    @Autowired
    private IoUtil ioUtil;
    @Autowired
    private HttpUtil httpUtil;

    /**
     * 保存xls的方法
     *
     * @param is       文件的模板输入流;模板里面只有一行,就是title;主要是为了,区分列的顺序
     * @param dataList List是行,里面的元素也是List;里面的Map;键是标题头,值是 真正的结果
     */
    public void writeExcelModel(InputStream is, List dataList, OutputStream os) {
        /* 模板文件 */
        try {
            Workbook workbook = new HSSFWorkbook(is);
            /* 只要第一个sheet */
            Sheet sheet = workbook.getSheetAt(0);
            /* 读取标题的头部 */
            Row row = sheet.getRow(0);
            /* 存储所有的标题的头部 */
            Map<String, Integer> titleMap = new HashMap<String, Integer>();
            /* 取到每一列 */
            int titleCount = 0;
            for (Iterator iterator = row.cellIterator(); iterator.hasNext(); ) {
                Cell cellTemp = (Cell) iterator.next();
                titleMap.put(cellTemp.toString(), titleCount);
                titleCount++;
            }

            /*
             * 存储数据 外循环是行 内循环是列
             */
            int dataRow = 1;
            for (Iterator iterator = dataList.iterator(); iterator.hasNext(); ) {
                /*
                 * 取到row;模板中只有一行; 第二行
                 */
                Row row2 = sheet.createRow(dataRow);
                Map<String, Object> dataMap = (Map<String, Object>) iterator.next();

                /* 循环标题头部 */
                for (Iterator iterator2 = titleMap.entrySet().iterator(); iterator2.hasNext(); ) {
                    /* 键:是xls中的标题的头部,值是列的顺序 */
                    Entry me = (Entry) iterator2.next();
                    /* 创建的单元格是几列,取决于titleMap中的值 */
                    String key = me.getKey() + "";
                    int value = Integer.valueOf(me.getValue() + "");

                    /* 创建的是第几个单元格 */
                    Cell cell = row2.createCell(value);
                    /* 赋值的时候从dataMap中取值 */
                    cell.setCellValue(dataMap.get(key) + "");
                }
                dataRow++;
            }

            /* 在保存文件的时候需要一个outputStream */
            workbook.write(os);
            /* 保存文件 */
            workbook.close();
        } catch (IOException e) {
            log.error("保存xls失败了;", e);
        }
    }

    /**
     * 根据模板生成word文档
     *
     * @param is  模板文件
     * @param map image要传一个图片路径
     * @param os  输出流
     */
    public void writeWordModel(InputStream is, Map<String, String> map, OutputStream os) {
        try {
            XWPFDocument document = new XWPFDocument(is);
            List<XWPFParagraph> paragraphList = document.getParagraphs();
            /**
             * 在循环的时候对数据进行处理
             */
            for (Iterator iterator = paragraphList.iterator(); iterator.hasNext(); ) {
                XWPFParagraph xwpfParagraph = (XWPFParagraph) iterator.next();
                /* 获取每一行 */
                List<XWPFRun> runs = xwpfParagraph.getRuns();
                /* 设置内容 */
                for (Iterator iterator2 = runs.iterator(); iterator2.hasNext(); ) {
                    XWPFRun xwpfRun = (XWPFRun) iterator2.next();
                    /* 根据原来的字符串,修改模板 */
                    String text = this.ioUtil.replaceOperator(xwpfRun.toString(), map);
                    xwpfRun.setText(text, 0);
                }
            }

            /* 表格 */
            List<XWPFTable> tableList = document.getTables();
            for (Iterator iterator = tableList.iterator(); iterator.hasNext(); ) {
                XWPFTable xwpfTable = (XWPFTable) iterator.next();
                /* 获取行 */
                List<XWPFTableRow> rowsList = xwpfTable.getRows();
                for (Iterator iterator2 = rowsList.iterator(); iterator2.hasNext(); ) {
                    XWPFTableRow xwpfTableRow = (XWPFTableRow) iterator2.next();
                    /* 获取单元格 */
                    List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells();
                    for (Iterator iterator3 = tableCells.iterator(); iterator3.hasNext(); ) {
                        XWPFTableCell xwpfTableCell = (XWPFTableCell) iterator3.next();
                        /* 段落 */
                        List<XWPFParagraph> paragraphTempList = xwpfTableCell.getParagraphs();
                        for (Iterator iterator4 = paragraphTempList.iterator(); iterator4.hasNext(); ) {
                            XWPFParagraph xwpfParagraph = (XWPFParagraph) iterator4.next();
                            /* 设置内容 */
                            List<XWPFRun> runs = xwpfParagraph.getRuns();
                            for (Iterator iterator5 = runs.iterator(); iterator5.hasNext(); ) {
                                XWPFRun xwpfRun = (XWPFRun) iterator5.next();
                                String souText = xwpfRun.toString();
                                if (souText.startsWith("${image")) {
                                    souText = souText.replaceAll("\\$", "").replaceAll("\\{", "").replaceAll("\\}", "");
                                    String path = map.get(souText);
                                    if (path != null) {
                                        File pathFile = new File(path);
                                        FileInputStream fis = new FileInputStream(path);
                                        if (souText.indexOf("_01") != -1) {
                                            /* 添加图片 */
                                            XWPFPicture picture = xwpfRun.addPicture(fis, XWPFDocument.PICTURE_TYPE_PNG, pathFile.getName(),
                                                    Units.toEMU(180), Units.toEMU(140));
                                        } else if (souText.indexOf("_02") != -1) {
                                            /* 添加图片 */
                                            XWPFPicture picture = xwpfRun.addPicture(fis, XWPFDocument.PICTURE_TYPE_PNG, pathFile.getName(),
                                                    Units.toEMU(220), Units.toEMU(143));
                                        } else {
                                            /* 添加图片 */
                                            XWPFPicture picture = xwpfRun.addPicture(fis, XWPFDocument.PICTURE_TYPE_PNG, pathFile.getName(),
                                                    Units.toEMU(100), Units.toEMU(100));
                                        }
                                        fis.close();
                                    }
                                    /* 清空单元格中的内容 */
                                    xwpfRun.setText("", 0);
                                } else {
                                    //System.out.println("====>" + souText);
                                    /* 根据原来的字符串,修改模板 */
                                    String text = this.ioUtil.replaceOperator(souText, map);
									/*log.info(xwpfRun.toString() + "=Table=getParagraphs===>" + text + "===" + map
										+ "====picSize:" + xwpfRun.getPictureText() + "===" + xwpfRun.getEmbeddedPictures().size());*/
                                    xwpfRun.setText(text, 0);
                                }
                            }
                        }
                    }
                }
            }

			/* 图片 
			List<XWPFPictureData> allPictureList = document.getAllPictures();
			for (Iterator iterator = allPictureList.iterator(); iterator.hasNext();)
			{
				XWPFPictureData xwpfPictureData = (XWPFPictureData) iterator.next();
				System.out.println("====" + xwpfPictureData.getFileName());
				byte[] picByte = xwpfPictureData.getData() ; 
				FileOutputStream fos = new FileOutputStream("d:/" + xwpfPictureData.getFileName());
				ByteInputStream bis = new ByteInputStream(picByte, picByte.length);
				 拷贝图片 
				this.fileUtil.copy(bis, fos,true);
			}*/

			/*List<XWPFPictureData> allPackagePictures = document.getAllPackagePictures();
			for (Iterator iterator = allPackagePictures.iterator(); iterator.hasNext();)
			{
				XWPFPictureData xwpfPictureData = (XWPFPictureData) iterator.next();
				System.out.println("====" + xwpfPictureData.getFileName());
			}

			https://blog.csdn.net/alice_qixin/article/details/71730346 
			try
			{
				FileInputStream fis = new FileInputStream(new File("d:/1.png"));
				String res = document.addPictureData(fis, XWPFDocument.PICTURE_TYPE_PNG);
				System.out.println("===>" + res);

				System.out.println("====" + document.getRelationById(res));
				CustomXWPFDocument customXWPFDocument = new CustomXWPFDocument(); 
				customXWPFDocument.createPicture(document.createParagraph(),document.getAllPictures().size()-1, 100, 100,"    ");
				fis.close();
				customXWPFDocument.close();
			} catch (InvalidFormatException e)
			{
				e.printStackTrace();
			}*/

            /* 将内容写到文件中 */
            document.write(os);
            document.close();
        } catch (Exception e) {
            log.error("保存docx失败了;", e);
        } finally {
            /* 相关的流要关闭 */
            try {
                if (os != null) {
                    os.close();
                    os = null;
                }
            } catch (IOException e) {
                log.error("关闭失败了;", e);
            }
            try {
                if (is != null) {
                    is.close();
                    is = null;
                }
            } catch (IOException e) {
                log.error("关闭失败了;", e);
            }
        }
    }

    /**
     * 读取xls文件内容  返回一个map集合
     *
     * @param is 文件流
     * @return Map:键是sheet的名字,值是List,List里面放的是Map;map的键是标题,值是单元格的值
     * @throws IOException 读取文件异常
     */

    public Map<String, List> readExcel(InputStream is, String extendName) throws IOException {
        Workbook workbook = null;
        //存放xls文件数据
        Map<String, List> resultMap = new HashMap<String, List>();
        try {
            if ("xlsx".equalsIgnoreCase(extendName)) {
                workbook = new XSSFWorkbook(is);
            } else {
                workbook = new HSSFWorkbook(is);
            }

            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                /* 只要第一个sheet */
                Sheet sheet = workbook.getSheetAt(i);
                /* 读取每一个sheet的内容 */
                List<Map<String, Object>> resultList = readExcelSheet(sheet);
                resultMap.put(sheet.getSheetName(), resultList);
            }
        } catch (Exception e) {
            log.error("读取文件报错了,扩展名:{}", extendName, e);
        } finally {
            if (workbook != null) {
                workbook.close();
                workbook = null;
            }
            if (is != null) {
                is.close();
                is = null;
            }
        }
        return resultMap;
    }

    /**
     * 读取sheet表里面的数据
     *
     * @param sheet
     * @return
     */
    private List<Map<String, Object>> readExcelSheet(Sheet sheet) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        /* 读取标题的头部 */
        Row row = sheet.getRow(0);
        /* 存储所有的标题的头部信息  key:序号  value:值 */
        Map<Integer, String> titleMap = new HashMap<Integer, String>();
        //存储数据 key:序号 value:数据
        //获取总列数
        int columnNum = row.getPhysicalNumberOfCells();
        for (int titleCount = 0; titleCount < columnNum; titleCount++) {
            Cell cellTemp = row.getCell(titleCount);
            if (cellTemp != null) {
                titleMap.put(titleCount, cellTemp.toString());
            }
        }
        log.info("--getLastRowNum-->{}", sheet.getLastRowNum());
        // 处理当前页，循环读取每一行  跳过title行  直接读取数据
        for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
            //存放xls文件中每一行的数据   Map中数据： key：title value：title值
            Map<String, Object> result = new HashMap<String, Object>();
            // HSSFRow表示行
            Row hssfRow = sheet.getRow(rowNum);
            /* 循环titleMap */
            for (Iterator iterator = titleMap.entrySet().iterator(); iterator.hasNext(); ) {
                Entry<Integer, String> me = (Entry<Integer, String>) iterator.next();
                Integer key = me.getKey();
                String val = me.getValue();
                /* 按照titleMap对应的列进行查询,并且放到结果的容器中 */
                Cell cell = hssfRow.getCell(key);
                if (cell != null) {
                    /* 键是title的列的名字,值是单元格的值 */
                    result.put(val, cell.toString());
                } else {
                    result.put(val, "");
                }
            }
            resultList.add(result);
        }
        return resultList;
    }

    /**
     * 根据html内容生成word文档
     *
     * @param url html内容
     * @param os   输出流
     */
    public void htmlToWord(String url, OutputStream os) {
        try (XWPFDocument document = new XWPFDocument()) {
            /* 设置网址 */
            this.convertHtmlToWord(document, url);
            document.write(os);
        } catch (Exception e) {
            log.error("html转word异常", e);
        }
    }

    /**
     * 转换html为word
     * @param document  文档对象
     * @param url   网址
     * @throws Exception    异常
     */
    private void convertHtmlToWord(XWPFDocument document, String url) throws Exception {
        List<String> paraList = Arrays.asList("div","p", "span", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "li", "ol", "table", "tr");
        String imgTagStr = "img";
        String imgSrcStr = "src";
        /* 获取网址的内容 */
        Connection connect = Jsoup.connect(url);
        connect.timeout(ConstatFinalUtil.SECOND * 10);
        Document jsoupDocu = connect.get();
        Elements elements = jsoupDocu.body().children();

        /* 根据网址不同的标签生成不同的word文档内容 */
        for (Element element : elements) {
            String tagName = element.tagName();
            if (paraList.contains(tagName)) {
                XWPFParagraph paragraph = document.createParagraph();
                XWPFRun run = paragraph.createRun();
                run.setText(element.text());
            } else if (element.tagName().equals(imgTagStr)) {
                String src = element.attr(imgSrcStr);
                try (InputStream inputStream = this.downloadImage(src)) {
                    if (inputStream != null) {
                        XWPFParagraph paragraph = document.createParagraph();
                        XWPFRun run = paragraph.createRun();
                        run.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_JPEG, src, Units.toEMU(200), Units.toEMU(200));
                    }
                }
            }
        }
    }

    /**
     * 根据网址下载图片
     * @param imgUrl    图片网址
     * @return  输入流
     * @throws IOException  异常
     */
    private InputStream downloadImage(String imgUrl) throws IOException {
        Map<String, String> headerMap = new HashMap<>();
        Map<String, String[]> paramsMap = new HashMap<>();
        Map<String, List<String>> responseMap = new HashMap<>();
        return this.httpUtil.methodGetInputStream(imgUrl, headerMap, paramsMap, responseMap);
    }
}